#pragma once

#include<iostream>
#include<queue>
#include<vector>
#include"Thread.hpp"
#include"Mutex.hpp"
#include"Cond.hpp"
#include<string>
#include"Task.hpp"
#include<sstream>

template<class T>
class ThreadPool
{
private:
    bool QueueEmpty()
    {
        return _q.empty();
    }

    void Routine(const std::string& name)
    {
        while(1)
        {
            T t;
            {
                LockGuard lock_guard(&_lock);
                while(QueueEmpty() && _is_running)
                {
                    _thread_wait_num++;
                    _cond.Wait(_lock);
                    _thread_wait_num--;
                }
                if(!_is_running && QueueEmpty())
                {
                    LOG(LogLevel::DEBUG) << "线程池退出 && 任务队列为空," << name << " 退出";
                    break;
                }
                t = _q.front();
                _q.pop();
            }
            t();
        }
    }

    ThreadPool(int thread_num = 5)
        :_thread_num(thread_num)
        ,_is_running(false)
        ,_thread_wait_num(0)
    { 
        for(int i = 0; i < thread_num; i++)
        {
            std::string name = "thread-" + std::to_string(i + 1);
            _threads.emplace_back([this](const std::string& name)
            {
                this->Routine(name);
            }
            , name);
        }
        LOG(LogLevel::INFO) << "thread pool create success";
    }

    ThreadPool<T>& operator=(const ThreadPool<T>& t) = delete;

    ThreadPool(const ThreadPool<T>& t) = delete;

public:
    void Start()
    {
        if(_is_running)
            return;
        _is_running = true;
        for(auto& e : _threads)
        {
            e.Start();
        }
        LOG(LogLevel::INFO) << "thread pool running success";
    }

    void Stop()
    {
        if(!_is_running)
            return;
        _is_running = false;
        if(_thread_wait_num)
            _cond.NotifyAll();
    }

    void Wait()
    {
        for(auto& e : _threads)
        {
            e.Join();
        }
        LOG(LogLevel::INFO) << "thread pool wait success";
    }

    void EnQueue(const T& in)
    {
        if(!_is_running)
            return;
        LockGuard lock_guard(&_lock);
        _q.push(in);
        if(_thread_wait_num > 0)
            _cond.NotifyOne();
    }

    static std::string HexToString(ThreadPool<T>* addr)
    {
        // char* buff[64];
        // snprintf(buff, sizeof(buff), "%p", addr);
        std::stringstream ss;
        ss << addr;
        return ss.str();
    }

    static ThreadPool<T>* GetInstance()
    {
        if(!_instance)
        {
            _instance = new ThreadPool<T>();
            LOG(LogLevel::DEBUG) << "线程池单例首次被使用，创建并初始化，addr:" << HexToString(_instance);
            _instance->Start();
        }
        else
        {
            LOG(LogLevel::DEBUG) << "线程池单例已经存在，直接获取，addr:" << HexToString(_instance);
        }
        return _instance;
    }

private:
    std::queue<T> _q;
    std::vector<Thread> _threads;
    int _thread_num;
    Mutex _lock;
    Cond _cond;
    bool _is_running;
    int _thread_wait_num;
    static ThreadPool<T>* _instance;
};

template<class T>
ThreadPool<T>* ThreadPool<T>::_instance = nullptr;